package com.gitee.taotaojs.util.file;

import com.gitee.taotaojs.util.StringUtil;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import sun.misc.BASE64Encoder;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;
import java.time.LocalDate;

/**
 * 文件工具类
 *
 * @author TaoTaojs
 * @date 2020/7/6 9:38 AM
 * <p>Description</p>
 * <h1>文件操作工具</h1>
 * <h2>简介</h2>
 * 文件操作工具类
 * <h3>主要功能：</h3>
 * <ol>
 *     <li>获取文件的MD5值</li>
 * </ol>
 * 关联类:
 * 参考链接：
 * History: <br/>
 * <author>        <time>                      <version>          <desc>
 * TaoTaojs        2020/7/6 9:38 AM                V1.0           获取文件的MD5值
 */
public final class FileUtil {

    private static String tmpFolder;

    private static String nasDir;

    private static String s = "/";

    private FileUtil() {
        throw new IllegalStateException("Utility class");
    }

    /**
     * 返回本地保存的文件夹绝对路径，同时创建该文件夹
     */
    public static String getLocalFolderAbsolutePath(String type) {
        LocalDate today = LocalDate.now();
        if (StringUtils.isEmpty(type)) {
            type = "upload";
        }
        String dateFilePath = today.getYear() + s + today.getMonthValue() + s + today.getDayOfMonth() + s + type;
        File uploadFolder = new File(tmpFolder + s + dateFilePath);
        if (!uploadFolder.exists()) {
            uploadFolder.mkdirs();
        }
        return uploadFolder.getAbsolutePath();
    }

    /**
     * 返回本地保存的文件夹相对路径，同时创建该文件夹
     */
    public static String getLocalFolderRelativePath(String type) {
        LocalDate today = LocalDate.now();
        if (StringUtils.isEmpty(type)) {
            type = "upload";
        }
        String dateFilePath = today.getYear() + s + today.getMonthValue() + s + today.getDayOfMonth() + s + type;
        File uploadFolder = new File(tmpFolder + s + dateFilePath);
        if (!uploadFolder.exists()) {
            uploadFolder.mkdirs();
        }
        return dateFilePath;
    }

    public static String saveFile2Local(InputStream is, String localFolderPath, String localFilename) throws IOException {
        File saveDir = new File(localFolderPath);
        if (!saveDir.exists()) {
            saveDir.mkdirs();
        }
        File target = new File(localFolderPath + "/" + localFilename);
        FileOutputStream os = null;
        try {
            os = new FileOutputStream(target);
            byte[] buffer = new byte[8192];

            int bytesRead;
            while((bytesRead = is.read(buffer, 0, 8192)) != -1) {
                os.write(buffer, 0, bytesRead);
            }
        } finally {
            if (os != null) {
                os.close();
            }
            if (is != null) {
                is.close();
            }
        }
        return "";
    }

    public static String downloadFile(String urlStr, String localFolderPath,String localFilename) throws IOException {
        URL url = new URL(urlStr);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        // 设置超时间为3秒
        conn.setConnectTimeout(3 * 1000);
        // 得到输入流
        InputStream inputStream = conn.getInputStream();
        // 获取自己数组
        byte[] getData = readInputStream(inputStream);
        // 文件保存位置
        File saveDir = new File(localFolderPath);
        if (!saveDir.exists()) {
            saveDir.mkdirs();
        }
        File file = new File(saveDir + File.separator + localFilename);
        FileOutputStream fos = new FileOutputStream(file);
        fos.write(getData);
        if (fos != null) {
            fos.close();
        }
        if (inputStream != null) {
            inputStream.close();
        }
        return file.getCanonicalPath();
    }

    /**
     * 从输入流中获取字节数组
     *
     * @param inputStream
     * @return
     * @throws IOException
     */
    public static byte[] readInputStream(InputStream inputStream) throws IOException {
        byte[] buffer = new byte[1024];
        int len = 0;
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        while ((len = inputStream.read(buffer)) != -1) {
            bos.write(buffer, 0, len);
        }
        bos.close();
        return bos.toByteArray();
    }

    /**
     * base64图片转路径(临时文件)
     * @param base64Img
     * @return
     */
    public static String base64ImgToPath(String base64Img) {
        try {
            // 解码，然后将字节转换为文件
            byte[] bytes = java.util.Base64.getDecoder().decode(base64Img); // 将字符串转换为byte数组
            //File tempFile = createTempFile(".jpg");
            File tempFile = new File(tmpFolder + s + System.currentTimeMillis() + StringUtil.getNumberRandom(5) + ".jpg");
            if (tempFile.exists()) {
                tempFile.delete();
            }
            FileOutputStream fos = new FileOutputStream(tempFile);
            fos.write(bytes, 0, bytes.length);
            fos.flush();
            fos.close();
            return tempFile.getAbsolutePath();
        } catch (Exception e) {
            log.error("base64图片转路径失败", e);
            throw NormalBizException.instance("base64图片转路径失败");
        }
    }

    public static File createTempFile(String suffix) throws IOException {
        File tempFile = File.createTempFile("temp", suffix);
        tempFile.deleteOnExit();
        return tempFile;
    }

    public static String imageUrlToBase64(String imgUrl) {
        InputStream inputStream = null;
        ByteArrayOutputStream outputStream = null;
        byte[] buffer = null;
        try {
            // 创建URL
            URL url = new URL(imgUrl);
            // 创建链接
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            conn.setConnectTimeout(5000);
            inputStream = conn.getInputStream();
            outputStream = new ByteArrayOutputStream();
            // 将内容读取内存中
            buffer = new byte[1024];
            int len = -1;
            while ((len = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, len);
            }
            buffer = outputStream.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    // 关闭inputStream流
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (outputStream != null) {
                try {
                    // 关闭outputStream流
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        // 对字节数组Base64编码
        return new BASE64Encoder().encode(buffer).replaceAll("[\\s*\t\n\r]", "");

    }

    /**
     * 将七牛路径保存至nas
     *
     * @param filePath 如 2020/6/2/idcardocr/15910876435328021_backidCardImage.jpg
     * @param isPrivate 是否私有 是 true 否 false
     * @return
     */
    public static void saveQiniuUrlToNas(String filePath, Boolean isPrivate) {
        if (filePath == null) {
            return;
        }
        try {
            String[] filePathStr = filePath.split("/");
            String localFilename = filePathStr[filePathStr.length-1];
            String localFolderPath = nasDir + "/" + filePath.replaceAll("/" + localFilename, StringUtils.EMPTY);

            FileUtil.downloadFile(QiniuUtil.getFileUrl(filePath, isPrivate), localFolderPath, localFilename);
        } catch (IOException e) {
            log.error("下载七牛图片到nas失败", e);
            throw NormalBizException.instance("下载七牛图片到nas失败");
        }
    }

    /**
     * inputStream 转 File
     */
    public static File inputStreamToFile(InputStream ins, String name) {
        try {
            File file = new File(System.getProperty("java.io.tmpdir") + File.separator + name);
            if (file.exists()) {
                return file;
            }
            OutputStream os = new FileOutputStream(file);
            int bytesRead;
            int len = 8192;
            byte[] buffer = new byte[len];
            while ((bytesRead = ins.read(buffer, 0, len)) != -1) {
                os.write(buffer, 0, bytesRead);
            }
            os.close();
            ins.close();
            return file;
        } catch (IOException e) {
            log.error("inputStream转File失败", e);
            throw NormalBizException.instance("inputStream转File失败");
        }
    }

    @Value("${tmp.path}")
    public void setTmpFolder(String tmpFolder) {
        FileUtil.tmpFolder = tmpFolder;
    }

    @Value("${qnvip.nasDir}")
    public void setNasDir(String nasDir) {
        FileUtil.nasDir = nasDir;
    }

    @Data
    public static class UploadResult {
        private String filename; // 文件名称
        private String filePath; // 本地文件完整路径
        private String qiniuKey; // 上传七牛路径
    }

    public static byte[] createChecksum(String url, String filename) {
        try {
            String filePath = FileUtil.downloadFile(url, tmpFolder, filename);
            File file = new File(filePath);
            InputStream fis = new FileInputStream(file);
            byte[] buffer = new byte[1024];
            MessageDigest complete = MessageDigest.getInstance("SHA-256");
            int numRead;

            do {
                numRead = fis.read(buffer);
                if (numRead > 0) {
                    complete.update(buffer, 0, numRead);
                }
            } while (numRead != -1);

            fis.close();
            file.delete();
            return complete.digest();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取网络文件hash值
     *
     * @param url 网络文件地址
     * @param filename 本地文件名称
     * @return
     * @throws Exception
     */
    public static String getMD5Checksum(String url, String filename) {
        byte[] b = createChecksum(url, filename);
        String result = "";
        for (int i = 0; i < b.length; i++) {
            result += Integer.toString((b[i] & 0xff) + 0x100, 16).substring(1);
        }
        return result;
    }
}
